package org.lemon.cla.jwt;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.lemon.cla.enums.HttpStatusEnum;
import org.lemon.cla.exception.BusinessException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

// 导入你的 User 实体类
import org.lemon.cla.pojo.User;

@Component
public class JwtUtil {

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration}")
    private long expiration; // JWT 有效期，单位毫秒

    /**
     * 生成 JWT Token
     * 改进：直接传入你的 User 实体（它实现了 UserDetails），这样可以访问更多自定义字段
     */
    public String generateToken(User user) { // 更改参数类型为你的 User 实体
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            Date issuedAt = new Date();
            Date expiresAt = new Date(issuedAt.getTime() + expiration);

            // 获取用户角色字符串
            String roles = user.getAuthorities().stream()
                    .map(grantedAuthority -> grantedAuthority.getAuthority())
                    .collect(Collectors.joining(","));

            Map<String, Object> claims = new HashMap<>();
            claims.put("roles", roles);
            // 将额外的用户信息添加到 claims
            claims.put("userId", user.getUserId()); // 添加用户ID
            claims.put("realName", user.getRealName()); // 添加真名
            claims.put("email", user.getEmail()); // 添加邮箱
            // 根据需要添加更多字段，比如 phone, avatarUrl 等

            return JWT.create()
                    .withSubject(user.getUsername()) // 通常主题是用户名
                    .withIssuedAt(issuedAt)
                    .withExpiresAt(expiresAt)
                    .withPayload(claims) // 使用包含额外信息的 claims
                    .sign(algorithm);
        } catch (JWTCreationException exception){
            throw new RuntimeException("生成 JWT Token 错误", exception);
        }
    }

    /**
     * 从 Token 中提取用户名 (subject)
     */
    public String extractUsername(String token) {
        DecodedJWT jwt = decodeToken(token);
        return jwt.getSubject();
    }

    /**
     * 验证 Token 是否有效
     * 验证时，JWT 库会自动检查过期时间、签名等。
     * 额外与传入的 UserDetails (通常从数据库加载) 的用户名进行比对。
     */
    public boolean validateToken(String token, UserDetails userDetails) {
        final String extractedUsername = extractUsername(token);
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withSubject(extractedUsername) // 验证主题
                    .build();

            verifier.verify(token); // 验证签名和过期时间
            return extractedUsername.equals(userDetails.getUsername()); // 验证用户名匹配
        } catch (JWTVerificationException exception){
            // 如果验证失败（签名不匹配，Token过期等），会抛出异常
            return false;
        }
    }

    /**
     * 解码 JWT Token
     */
    public DecodedJWT decodeToken(String token) {
        try {
            return JWT.decode(token);
        } catch (JWTVerificationException exception){
            // 如果 Token 格式不正确，解码也会失败
//            throw new RuntimeException("解码 JWT Token 错误: " + exception.getMessage(), exception);
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "解码 JWT Token 错误: " + exception.getMessage());
        }
    }

    /**
     * 从 Token 中提取特定声明 (String 类型)
     */
    public String extractStringClaim(String token, String claimName) { // 更改方法名为 extractStringClaim
        DecodedJWT jwt = decodeToken(token);
        return jwt.getClaim(claimName).asString();
    }

    /**
     * 从 Token 中提取特定声明 (Integer 类型)
     */
    public Integer extractIntegerClaim(String token, String claimName) { // 新增方法
        DecodedJWT jwt = decodeToken(token);
        return jwt.getClaim(claimName).asInt();
    }

    /**
     * 从 Token 中提取所有声明
     */
    public Map<String, Object> extractAllClaims(String token) { // 新增方法
        DecodedJWT jwt = decodeToken(token);
        Map<String, Object> claimsMap = new HashMap<>();
        jwt.getClaims().forEach((key, value) -> claimsMap.put(key, value.asString())); // 默认转换为 String，实际类型根据需要调整
        return claimsMap;
    }
}